/*
 * Galaxium Messenger
 * Copyright (C) 2007 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

using Anculus.Core;

namespace Galaxium.Protocol.Msn
{
	[MsnCommand ("MSG", MsnConnectionType.Any, typeof (MSGCommandParser))]
	[PayloadCommand]
	[TransactionCommand (false, true)]
	public class MSGCommand : ContentCommand
	{
		public MSGAckType AckType
		{
			get
			{
				switch (GetArgument (0))
				{
				case "N":
					return MSGAckType.NakOnly;
				case "A":
					return MSGAckType.Always;
				case "D":
					return MSGAckType.AlwaysP2P;
				default:
					return MSGAckType.None;
				}
			}
			set
			{
				switch (value)
				{
				case MSGAckType.Always:
					SetArgument (0, "A");
					break;
				case MSGAckType.AlwaysP2P:
					SetArgument (0, "D");
					break;
				case MSGAckType.NakOnly:
					SetArgument (0, "N");
					break;
				case MSGAckType.None:
					SetArgument (0, "U");
					break;
				}
			}
		}
		
		public IMsnEntity Source
		{
			get
			{
				if (Incoming)
					return Session.FindContact (GetArgument (0));
				
				return Session.Account;
			}
		}
		
		public override bool ExpectResponse
		{
			get { return (AckType == MSGAckType.Always) || (AckType == MSGAckType.AlwaysP2P); }
		}
		
		public MSGCommand (MsnSession session)
			: base (session)
		{
			AckType = MSGAckType.None;
			Payload = new byte[0];
		}
		
		public MSGCommand (MsnSession session, byte[] data)
			: base (session, data)
		{
		}
		
		public override byte[] ToByteArray ()
		{
			byte[] data = base.ToByteArray ();
			
			if (data.Length <= 1600)
				return data;
			
			// The following code handles multi packet messaging
			// to allow long messages to be sent over the switchboard
			// in multiple smaller chunks
			
			//TODO: this code can probably be optimised quite a lot
			// it could also ensure the maximum data per chunk by finding
			// the size of the first line & MIME and calculating the chunks
			// payload size from those
			
			byte[] payload = Payload;
			MessageBuilder mb = new MessageBuilder ();
			int payloadPerChunk = 1000;
			
			Guid messageId = Guid.NewGuid ();
			int chunks = (int)Math.Ceiling ((double)payload.Length / payloadPerChunk);
			
			MSGCommand cmd = new MSGCommand (Session, data);
			cmd.MIMEHeader["Message-ID"] = messageId.ToString ("B");
			cmd.MIMEHeader["Chunks"] = chunks.ToString ();
			
			for (int i = 0; i < chunks; i++)
			{
				if (i > 0)
				{
					cmd.MIMEHeader.Clear ();
					cmd.MIMEHeader["Message-ID"] = messageId.ToString ("B");
					cmd.MIMEHeader["Chunk"] = i.ToString ();
				}
				
				byte[] chunkPayload = new byte [Math.Min (payloadPerChunk, payload.Length - (i * payloadPerChunk))];
				Array.Copy (payload, i * payloadPerChunk, chunkPayload, 0, chunkPayload.Length);
				
				cmd.Payload = chunkPayload;
				
				mb.Append (cmd.ToByteArray ());
			}
			
			return mb.GetByteArray ();
		}
	}
	
	public class MSGCommandParser : ContentCommandParser
	{
		public MSGCommandParser ()
			: base (typeof (MSGCommand))
		{
		}
	}
}
